﻿using System.Reflection;
using System.Windows.Controls;
using System.ComponentModel;

// Author: Miroslav Matula m.matula@alutam.cz 
// Date : 31/8/2010

namespace System.Windows.Controls
{
  public class DataGridToolBarOData : DataGridToolBarBase
  {
    public DataGridToolBarOData()
    {
      ButtonRefreshVisible = true;
    }

    #region -- ODataSource ----------------------------
    /// <summary>
    /// Reference to ODataSource.
    /// </summary>
    /// <example>XAML
    /// <code>
    /// ODataSource="{ Binding ElementName=domainDataSourceNameControl, Mode=OneTime}"
    /// </code>
    /// </example>
    public object ODataSource
    {
      get { return GetValue(ODataSourceProperty); }
      set { SetValue(ODataSourceProperty, value); }
    }

    public static readonly DependencyProperty ODataSourceProperty =
        DependencyProperty.Register("ODataSource", typeof(object), typeof(DataGridToolBarOData), new PropertyMetadata(null, new PropertyChangedCallback(OnDomainDataSourceChanged)));

    private static void OnDomainDataSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
      if(e.OldValue != null) ((DataGridToolBarOData)d).DetachODataSource(e.OldValue);
      ((DataGridToolBarOData)d).AttachODataSource(e.NewValue);
    }

    private void DetachODataSource(object ODataSource_)
    {
      this.ClearValue(IsBusyProperty); // has binding to DomainSource
      this.ClearValue(CanLoadProperty);// has binding to DomainSource
      _eiDataLoaded.RemoveEventHandler(ODataSource_, new AsyncCompletedEventHandler(ODataSource_LoadedData));
      _eiSubmittedChanges.RemoveEventHandler(ODataSource_, new AsyncCompletedEventHandler(ODataSource_SubmittedChanges));
    }
    //-------
    private MethodInfo _miCancelLoading;
    private MethodInfo _miCancelSubmitting;
    private MethodInfo _miClear;
    private MethodInfo _miSubmitChanges;
    private MethodInfo _miRefreshData;
    private MethodInfo _miRejectChanges;
    private MethodInfo _miClearFilterDescription2;
    private MethodInfo _miAndFilterDescription2;
    private MethodInfo _miApplyFilterDescription2;
    private PropertyInfo _piHasChanges;
    private PropertyInfo _piIsLoading;
    private PropertyInfo _piIsSubmitting;
    private EventInfo _eiDataLoaded;
    private EventInfo _eiSubmittedChanges;

    private void AttachODataSource(object ODataSource_)
    {
      Type dsType = ODataSource.GetType();
      if(dsType.Name != "ODataSource") throw new ArgumentException("Accept only clr-namespace:System.Windows.Controls.ODataSource; assembly=Slma.Windows.Controls.OData");

      _miClear = dsType.GetMethod("Clear", new Type[] { });
      _miSubmitChanges = dsType.GetMethod("SubmitChanges", new Type[] { typeof(Action<AsyncCompletedEventArgs>) });
      _miRefreshData = dsType.GetMethod("RefreshData", new Type[] {});
      _miRejectChanges = dsType.GetMethod("RejectChanges", new Type[] {});
      _miCancelLoading = dsType.GetMethod("CancelLoading", new Type[] {});
      _miCancelSubmitting = dsType.GetMethod("CancelSubmitting", new Type[] { });

      _miClearFilterDescription2 = dsType.GetMethod("ClearFilterDescription2", new Type[] { });
      _miApplyFilterDescription2 = dsType.GetMethod("ApplyFilterDescription2", new Type[] { });
      _miAndFilterDescription2 = dsType.GetMethod("AndFilterDescription2", new Type[] { typeof(string), typeof(int), typeof(string) });
      
      _piHasChanges = dsType.GetProperty("HasChanges",BindingFlags.Instance | BindingFlags.Public);
      _piIsLoading = dsType.GetProperty("IsLoading", BindingFlags.Instance | BindingFlags.Public);
      _piIsSubmitting = dsType.GetProperty("IsSubmitting", BindingFlags.Instance | BindingFlags.Public);

      _eiDataLoaded = dsType.GetEvent("DataLoaded", BindingFlags.Instance | BindingFlags.Public);
      _eiDataLoaded.AddEventHandler(ODataSource_, new AsyncCompletedEventHandler(ODataSource_LoadedData));

      _eiSubmittedChanges = dsType.GetEvent("SubmittedChanges", BindingFlags.Instance | BindingFlags.Public);
      _eiSubmittedChanges.AddEventHandler(ODataSource_, new AsyncCompletedEventHandler(ODataSource_SubmittedChanges));

      this.SetBinding(CanLoadProperty, new Data.Binding("CanLoad") { Source = ODataSource_ });
      this.SetBinding(IsBusyProperty, new Data.Binding("IsBusy") { Source = ODataSource_ });

   
      IsHitTestVisible = DataGrid != null;
    }
    //-------
    #endregion

    private void ODataSource_LoadedData(object sender, AsyncCompletedEventArgs e)
    {
        if(e.Cancelled) SetMessageCancelled();
        else if(e.Error != null) SetMessageError(e.Error.Message);
    }

    private void ODataSource_SubmittedChanges(object sender, AsyncCompletedEventArgs e)
    {
        if(e.Cancelled) SetMessageCancelled();
        else if(e.Error != null) SetMessageError(e.Error.Message);
    }

    public override bool IsLoading { get { return (bool)_piIsLoading.GetValue(ODataSource, null); } }

    public override bool IsSubmitting { get { return (bool)_piIsSubmitting.GetValue(ODataSource, null); } }

    //------------------
    override public void ApplyFiltr()
    {
      if(ODataSource == null) return;
      FilterMessage.Inlines.Clear();
      _miClearFilterDescription2.Invoke(ODataSource,new object[0]);
      bool firstItem = true;
      foreach(var item in this.Filter) {
        _miAndFilterDescription2.Invoke(ODataSource, new object[]{item.ColumnName,(int)item.Operator,item.Value});

        if(!firstItem) FilterMessage.Inlines.Add(new Documents.Run() { Text = " " + LangResources.LocalizedStrings.DGTB_and + " " });
        FilterMessage.Inlines.Add(new Documents.Run() { Text = item.Title });
        FilterMessage.Inlines.Add(new Documents.Run() { Text = " " + item.Mark + " ", Foreground = MessageOperatorBrush });
        FilterMessage.Inlines.Add(new Documents.Run() { Text = item.Value, FontWeight = FontWeights.Black });
        firstItem = false;
      }
      _miApplyFilterDescription2.Invoke(ODataSource, new object[0]);
      OnFilter(new HandledEventArgs());

      /*
      if(ODataSource == null) return;
      FilterMessage.Inlines.Clear();

      FilterDescriptorOData fd_root = null;
      bool firstItem = true;
      foreach(var item in this.Filter) {
        var fd = new FilterDescriptorExpressionOData() { ColumnName = item.ColumnName, Operator = (FilterDescriptorExpressionOperator)item.Operator, Value = item.Value };
        if(firstItem) {
          fd_root = fd;
        } else {
          fd_root = new FilterDescriptorLogicalOData() {
            Operator = FilterDescriptorLogicalOperator.And,
            Left = fd_root,
            Right = fd
          };
        }

        if(!firstItem) FilterMessage.Inlines.Add(new Documents.Run() { Text = " " + LangResources.LocalizedStrings.DGTB_and + " " });
        FilterMessage.Inlines.Add(new Documents.Run() { Text = item.Title });
        FilterMessage.Inlines.Add(new Documents.Run() { Text = " " + item.Mark + " ", Foreground = MessageOperatorBrush });
        FilterMessage.Inlines.Add(new Documents.Run() { Text = item.Value, FontWeight = FontWeights.Black });
        firstItem = false;
      }
      ODataSource.FilterDescriptionsSecondPart = fd_root;
      OnFilter(new HandledEventArgs());
      */
    }
    //---------------------
    public override bool DataHasChanges
    {
      get
      {
        //return (ODataSource != null && ODataSource.HasChanges);
        return (ODataSource != null && (bool)_piHasChanges.GetValue(ODataSource,null));
      }
    }
    //---------------------
    public override void OnSubmitChanges(HandledEventArgs arg)
    {
      base.OnSubmitChanges(arg);
      if(!arg.Handled) {
        IsBusyCnt++;
        Action<AsyncCompletedEventArgs> callback = (completeArg) => {
          this.Dispatcher.BeginInvoke(() => {
            IsBusyCnt--;
            //if(canceled) SetMessageCancelled();
            //if(!string.IsNullOrEmpty(error)) SetMessageError(error);
          });
        };
        _miSubmitChanges.Invoke(ODataSource,new object[]{callback});
      }
    }
    //---------------------
    public override void OnRefreshData(HandledEventArgs arg)
    {
      base.OnRefreshData(arg);
      if(!arg.Handled) {
        //ODataSource.RefreshData(); //
        _miRefreshData.Invoke(ODataSource, new object[0]);
      }
    }

    //---------------------
    public override void OnRejectChanges(HandledEventArgs arg)
    {
      base.OnRejectChanges(arg);
      if(!arg.Handled) {
        //todo:if(this.ODataSource.IsSubmittingChanges) this.ODataSource.CancelSubmit();
        //this.ODataSource.RejectChanges();
        _miRejectChanges.Invoke(ODataSource, new object[0]);
      }
    }
    //---------------------
    public override void OnCancelLoadOrSubmitChanges()
    {
      if(IsLoading) {
        _miCancelLoading.Invoke(ODataSource, new object[0]) ;
        _miClear.Invoke(ODataSource, new object[0]);
      } if(IsSubmitting) {
        _miCancelSubmitting.Invoke(ODataSource, new object[0]);
      }
      base.OnCancelLoadOrSubmitChanges();
    }
    //---------------------
    protected override void AttachDataGrid(DataGrid dg_)
    {
      base.AttachDataGrid(dg_);
      IsHitTestVisible = ODataSource != null;
    }


  }
}
